Aprendizaje Profundo¶

Minicurso de Inteligencia Artificial

Introducción a Keras Sequential y API Funcional
¶

Profesores¶

  1. Alvaro Montenegro, PhD, ammontenegrod@unal.edu.co
  2. Daniel Montenegro, Msc, dextronomo@gmail.com
  3. Oleg Jarma, EstadĆ­stico, ojarmam@unal.edu.co

Asesora Medios y Marketing digital¶

  1. Maria del Pilar Montenegro, pmontenegro88@gmail.com

Contenido¶

  • Introducción a TensorFlow
  • Introducción a Keras
  • ĀæPor quĆ© elegir Keras?
  • Simulando Datos
  • Visualizando Datos
  • Construyendo Red Neuronal (DiseƱo))
  • Compilando Red Neuronal (Forma de Optimizar))
  • Entrenando Red Neuronal)
  • Visualizar Resultados de la Red
  • Redes Neuronales

Enlaces importantes¶

  1. Repositorio del mini curso
  2. Repositorio Aprendizaje Profundo
  3. Clases en vivo, Meeting ID: 860 5773 1334, Passcode: 392083
  4. Clases grabadas

Introducción a TensorFlow¶

La mejor introducción a esta biblioteca fundamental de inteligencia artificial es entrando a la documentación oficial:

diosito

[Volver]

Introducción a Keras¶

Keras no es mÔs que una API funcionando sobre algún motor tensorial (Por ejemplo, TensorFlow).

Igual que antes, no hay nada mejor que ir a los sitios oficiales y chequear por sí mismxs la documentación oficial:

diosito2

[Volver]

¿Por qué elegir Keras?¶

PreguntƩmosle a dios Google:

dios_trends

[Volver]

Importando Librerías Necesarias¶

Como siempre, lo primero que debemos hacer es importar las librerĆ­as necesarias:

In [2]:
# LibrerĆ­a para manejo de tensores
import tensorflow as tf
# API para AI sobre motor de tensores
from tensorflow import keras
# Manejo de arreglos
import numpy as np
# Dibujitos
import matplotlib.pyplot as plt

[Volver]

Simulando Datos¶

En esta ocasión y por ser la introducción, mostraremos que el proceso de optimización visto en clase (usando JAX), es equivalente a construir una red neuronal artificial.

Para esto, simulemos unos datos de prueba:

In [3]:
# Genera datos espaciados uniformemente
x=np.linspace(-10,10,50)
# Modelo generado a partir de las entradas
y=2*x**2+3*x+5*np.random.normal(0,4,size=len(x))

Observemos algo de los datos simulados:

In [4]:
print(x)
[-10.          -9.59183673  -9.18367347  -8.7755102   -8.36734694
  -7.95918367  -7.55102041  -7.14285714  -6.73469388  -6.32653061
  -5.91836735  -5.51020408  -5.10204082  -4.69387755  -4.28571429
  -3.87755102  -3.46938776  -3.06122449  -2.65306122  -2.24489796
  -1.83673469  -1.42857143  -1.02040816  -0.6122449   -0.20408163
   0.20408163   0.6122449    1.02040816   1.42857143   1.83673469
   2.24489796   2.65306122   3.06122449   3.46938776   3.87755102
   4.28571429   4.69387755   5.10204082   5.51020408   5.91836735
   6.32653061   6.73469388   7.14285714   7.55102041   7.95918367
   8.36734694   8.7755102    9.18367347   9.59183673  10.        ]
In [5]:
print(y)
[164.51293268 125.06310909 126.09615855 172.6455916   82.48431536
 110.64634991  96.13407121  88.33052181  48.15878265  69.74792564
  40.75117108  41.59893563  27.89987563  53.60668475  50.8516986
 -30.1562971   17.51811256  48.74021386   5.30598157   4.54312822
   7.29011522 -14.50833753  33.65527705  -2.61214908 -29.67285518
 -22.37158368  28.71740286  23.09563483  28.92067908  -4.19299509
  23.47884775  20.01359748  18.03393006   7.01915421  54.87707004
  28.83370182  76.93860316  71.32705485  41.29499325  83.07673062
  87.14710317  94.02270753 132.22015773 112.90137633 148.51421124
 147.41479907 199.07091548 171.87390047 204.41336392 255.16672667]

[Volver]

Visualizando Datos¶

En lo posible, trate de visualizar datos para tener una intuición sobre lo que estÔ pasando. Es claro que no siempre es posible hacerlo, pero exsiten, por ejemplo, técnicas de reducción de dimensión para dar una idea vaga de lo que estÔ pasando.

In [6]:
# Generar Lienzo
plt.figure(figsize=(15,7))
#Titulo del lienzo
plt.title("Visualización de Datos",fontsize=15)
#Dibujar datos
plt.plot(x,y,'o')
# Leyenda de los datos
plt.legend(["Datos"],fontsize=15)
# Nombrar Ejes
plt.xlabel("$Tiempo$",fontsize=15)
plt.ylabel("$Valor$",fontsize=15)
# Poner cuadrĆ­cula
plt.grid()
# Mostrar imagen
plt.show()

[Volver]

Construyendo Red Neuronal (Diseño)¶

Para construir nuestra primera red Neuronal, recuerde el siguiente dibujo:

Perceptron

Vemos que el dibujo opera de izquierda a derecha ($\rightarrow$), por lo que tiene sentido llamarlo Modelo Secuencial.

En este caso, usaremos una neurona (units) y la dimensión de entrada es unidimensional (input_shape)

In [9]:
model = keras.Sequential(
    keras.layers.Dense(units=1,input_shape=(1,))
    )

[Volver]

Compilando Red Neuronal (Forma de Optimizar)¶

Ahora que tenemos nuestra maqueta de las ecuaciones del modelo, elegimos una función de pérdida adecuada a nuestro problema y un optimizador para minimizar dicha pérdida:

In [10]:
model.compile(optimizer='sgd', loss='mean_squared_error')

[Volver]

Resumen de la Red Neuronal¶

El modelo creado y compilado tiene muchos otros mƩtodos interesantes.

Por ejemplo, podemos ver el resumen de lo que tiene la red.

In [11]:
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 1)                 2         
=================================================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
_________________________________________________________________

También es posible visualizar los modelos en forma de grafo, lo cual es muy útil para tener control global de la arquitectura del modelo:

In [12]:
from tensorflow.keras.utils import plot_model
In [13]:
plot_model(model,show_shapes=True)
Out[13]:

[Volver]

Entrenando Red Neuronal (Fancy para "Ajustar los datos")¶

[Volver]

Visualizar Resultados de la Red¶

In [16]:
#Obtener Pesos de la Red
w=model.get_weights();
print(w)
#Imprimir resultados
print("\nObjeto Pesos:",w)
print('\nNumber of Weights -> '+ str(len(w)))
print('\nw = ' + str(w[0][0]) +'(Weight)')
print('b = ' + str(w[1])+'("Weight"->Bias)')
[array([[4.415526]], dtype=float32), array([38.15945], dtype=float32)]

Objeto Pesos: [array([[4.415526]], dtype=float32), array([38.15945], dtype=float32)]

Number of Weights -> 2

w = [4.415526](Weight)
b = [38.15945]("Weight"->Bias)

[Volver]

Predecir valores dentro de los datos (Ver Regresión)¶

In [18]:
predecir=model.predict(x)
#print(predecir)
#np.vstack((predecir.reshape(-1,),y)).T

[Volver]

Visualizar Resultados¶

In [19]:
plt.figure(figsize=(15,7))
plt.plot(x,predecir,'r-',label='Model: y={:.2f}*x+{:.2f}'.format(w[0].item(),w[1].item()))
plt.plot(x,y,'o', label='Data')
plt.title('Plotting Model vs Data')
plt.legend(loc=0)
plt.show()

[Volver]

Mejorando Red Neuronal¶

In [ ]:
model2 = tf.keras.Sequential([
    keras.layers.Dense(units=5,input_shape=(1,),activation='softplus'),
    keras.layers.Dense(units=10,activation='softplus'),
    keras.layers.Dense(units=20,activation='softplus'),
    keras.layers.Dense(units=1),
    ])
model2.compile(optimizer='adam', loss='mean_squared_error')
model2.summary()
In [52]:
history=model2.fit(x, y, epochs=1000,verbose=0)
In [53]:
#Obtener Pesos de la Red
w2=model2.get_weights();
#Imprimir resultados
#print("\nObjeto Pesos:",w2)
#print('\nNumber of Weights -> '+ str(len(w2)))
#print('\nw = ' + str(w[0][0]) +'(Weight)')
#print('b = ' + str(w[1])+'("Weight"->Bias)')
In [54]:
x_test=np.linspace(x[0],x[-1],300)
predecir=model2.predict(x_test)
In [55]:
plt.figure(figsize=(15,8))
plt.plot(x_test,predecir,label='Model')
plt.plot(x,y,'o', label='Data')
plt.title('Plotting Model vs Data')
plt.legend(loc=0)
plt.show()
In [56]:
plt.figure(figsize=(15,8))
plt.plot(history.history['loss'],'r-',label='Loss')
plt.title('Plotting Model vs Data')
plt.legend(loc=0)
plt.show()

Datos más Retadores¶

In [57]:
trend=0.1
time=np.arange(0,100,0.1)
y=trend*time+np.sin(time)+np.random.normal(scale=0.5,size=len(time))
In [58]:
plt.figure(figsize=(15,8))
plt.title("Visualización de Datos",fontsize=15)
plt.plot(time,y,'-')
plt.legend(["Datos"],fontsize=15)
plt.xlabel("$x$",fontsize=15)
plt.ylabel("$y$",fontsize=15)
plt.grid()
plt.show()
In [59]:
model3 = tf.keras.Sequential([
    keras.layers.Dense(units=10,input_shape=(1,),activation='elu'),
    keras.layers.Dense(units=20,activation='elu'),
    keras.layers.Dense(units=30,activation='elu'),
    keras.layers.Dense(units=40,activation='elu'),
    keras.layers.Dense(units=50,activation='elu'),
    keras.layers.Dense(units=60,activation='elu'),
    keras.layers.Dense(units=70,activation='elu'),
    keras.layers.Dense(units=1)
    ])

model3.compile(optimizer='adam', loss='mean_squared_error')
model3.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_5 (Dense)              (None, 10)                20        
_________________________________________________________________
dense_6 (Dense)              (None, 20)                220       
_________________________________________________________________
dense_7 (Dense)              (None, 30)                630       
_________________________________________________________________
dense_8 (Dense)              (None, 40)                1240      
_________________________________________________________________
dense_9 (Dense)              (None, 50)                2050      
_________________________________________________________________
dense_10 (Dense)             (None, 60)                3060      
_________________________________________________________________
dense_11 (Dense)             (None, 70)                4270      
_________________________________________________________________
dense_12 (Dense)             (None, 1)                 71        
=================================================================
Total params: 11,561
Trainable params: 11,561
Non-trainable params: 0
_________________________________________________________________
In [60]:
history=model3.fit(time, y, epochs=10000,verbose=0)
In [61]:
#Obtener Pesos de la Red
w3=model3.get_weights();
#Imprimir resultados
#print("\nObjeto Pesos:",w2)
#print('\nNumber of Weights -> '+ str(len(w2)))
#print('\nw = ' + str(w[0][0]) +'(Weight)')
#print('b = ' + str(w[1])+'("Weight"->Bias)')
In [62]:
x_test=np.linspace(time[0],time[-1],3000)
predecir=model3.predict(x_test)
In [63]:
plt.figure(figsize=(15,8))
plt.plot(time,y,'-', label='Data')
plt.plot(x_test,predecir,'r',label='Model')
plt.title('Plotting Model vs Data')
plt.legend(loc=0)
plt.show()
In [64]:
plt.figure(figsize=(15,8))
plt.plot(history.history['loss'],'r-',label='Model')
plt.title('Plotting Model vs Data')
plt.legend(loc=0)
plt.show()

API Funcional¶

In [65]:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import keras
from tensorflow.keras.layers import Activation, Input,Dense
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
In [66]:
trend=0.1
time=np.arange(0,100,0.1)
y=trend*time+np.sin(time)+np.random.normal(scale=0.5,size=len(time))
In [67]:
inputs=Input(shape=(1,))
output=inputs
capas=10
dim=10
output=Activation('elu')(output)

for capa in range(capas):
    output=Dense(dim)(output)
    output=Activation('elu')(output)
    dim+=10
output=Dense(1)(output)

model=Model(inputs,output)
model.compile(loss='mse',optimizer='adam')
model.summary()
Model: "functional_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 1)]               0         
_________________________________________________________________
activation (Activation)      (None, 1)                 0         
_________________________________________________________________
dense_13 (Dense)             (None, 10)                20        
_________________________________________________________________
activation_1 (Activation)    (None, 10)                0         
_________________________________________________________________
dense_14 (Dense)             (None, 20)                220       
_________________________________________________________________
activation_2 (Activation)    (None, 20)                0         
_________________________________________________________________
dense_15 (Dense)             (None, 30)                630       
_________________________________________________________________
activation_3 (Activation)    (None, 30)                0         
_________________________________________________________________
dense_16 (Dense)             (None, 40)                1240      
_________________________________________________________________
activation_4 (Activation)    (None, 40)                0         
_________________________________________________________________
dense_17 (Dense)             (None, 50)                2050      
_________________________________________________________________
activation_5 (Activation)    (None, 50)                0         
_________________________________________________________________
dense_18 (Dense)             (None, 60)                3060      
_________________________________________________________________
activation_6 (Activation)    (None, 60)                0         
_________________________________________________________________
dense_19 (Dense)             (None, 70)                4270      
_________________________________________________________________
activation_7 (Activation)    (None, 70)                0         
_________________________________________________________________
dense_20 (Dense)             (None, 80)                5680      
_________________________________________________________________
activation_8 (Activation)    (None, 80)                0         
_________________________________________________________________
dense_21 (Dense)             (None, 90)                7290      
_________________________________________________________________
activation_9 (Activation)    (None, 90)                0         
_________________________________________________________________
dense_22 (Dense)             (None, 100)               9100      
_________________________________________________________________
activation_10 (Activation)   (None, 100)               0         
_________________________________________________________________
dense_23 (Dense)             (None, 1)                 101       
=================================================================
Total params: 33,661
Trainable params: 33,661
Non-trainable params: 0
_________________________________________________________________
In [68]:
history=model.fit(time,y,epochs=500,verbose=0)
In [69]:
x_test=np.linspace(time[0],time[-1],1000)
predecir=model.predict(x_test)
In [70]:
plt.figure(figsize=(15,8))
plt.plot(time[0:300],y[0:300],'-', label='Data')
plt.plot(x_test[0:300],predecir[0:300],'r',label='Model')
plt.title('Plotting Model vs Data')
plt.legend(loc=0)
plt.show()
In [71]:
plt.figure(figsize=(15,8))
plt.plot(history.history['loss'],'r-',label='Model')
plt.title('Plotting Model vs Data')
plt.legend(loc=0)
plt.show()

Otro Problema Interesante¶

MNIST¶

Construyamos una red convolucional para ver el beneficio sobre una red densa.

Para este proceso, realicemos nuestra rutina de cargar los datos, observar unos cuantos ejemplos y comprobar unas cuantas estadĆ­sticas:

Carga de Datos¶

In [2]:
# apunta  los datos
mnist = tf.keras.datasets.mnist

# lee los conjuntos de datos, los cuales vienen separados de antemano para entrenamiento y test
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()

# Verificar forma de los datos
print("Forma de los datos:",training_images.shape)
Forma de los datos: (60000, 28, 28)

Pre-procesamiento¶

In [3]:
# reshape para colocar los datos de entrenamiento en el fomato apropiado.
# Agrega una dimensión al final y  normaliza los datos
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0

# reshape para colocar los datos de test en el fomato apropiado. Agrega una dimensión al final y  normaliza los datos
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images/255.0

print("Nueva forma de los datos:", training_images.shape)
Nueva forma de los datos: (60000, 28, 28, 1)

Visualización¶

In [4]:
np.set_printoptions(linewidth=200,precision=2)

Definir el Modelo¶

  1. Capa 1: Conv2D con 32 filtros (kernels) de tamaño 3*3. Cada image viene en un tensor de tamaño 28 x 28 x 1. Los filtros son pasados por una f. de activación 'relu'.

  2. Capa 2. MaxPooling. Reduce cada filtro. Toma regiones secuenciales 2*2 y los reduce tomando el mÔximo de cada región. No usa f. de activación.

  3. Capa 3. Flatten. Toma todos los filtros resultantes de la capa MaxPooling y los organiza como un Ćŗnico tensor unidimensional

  4. Capa 4. Dense. Recibe el tensor saliente de la capa Flatten y genera una salida en 128 unidades, usando activación relu

  5. Capa 5. Dense. Recibe el tensor unidmensional de tamaƱo 128 y lo transforma en la salida de 10 unidades. Hay 10 clases.

El predictor es al final transformado por la acticación softmax para obtener una distribución de la posible clase para la imagend e entrada

In [10]:
model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), activation='relu', input_shape=(28, 28, 1)),
  tf.keras.layers.MaxPooling2D(2, 2),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(10, activation='softmax')
])

Es de Extremada importancia ver el diseƱo de la red para ver quƩ tantos parƔmetros tiene el modelo:

Compilar el modelo¶

In [13]:
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

Entrena el modelo¶

In [14]:
history = model.fit(training_images, training_labels, 
                    epochs=20, 
                    validation_split=0.2, 
                    batch_size=64,
                    callbacks=[accu_callback])
Epoch 1/20
750/750 [==============================] - 3s 4ms/step - loss: 0.1951 - accuracy: 0.9434 - val_loss: 0.0890 - val_accuracy: 0.9738
Epoch 2/20
750/750 [==============================] - 3s 4ms/step - loss: 0.0628 - accuracy: 0.9816 - val_loss: 0.0608 - val_accuracy: 0.9829
Epoch 3/20
750/750 [==============================] - 3s 4ms/step - loss: 0.0417 - accuracy: 0.9870 - val_loss: 0.0571 - val_accuracy: 0.9826
Epoch 4/20
750/750 [==============================] - ETA: 0s - loss: 0.0284 - accuracy: 0.9911
Se alcanzó un 98.5% de precisión en la validación! Cancelando Entrenamiento...
750/750 [==============================] - 3s 4ms/step - loss: 0.0284 - accuracy: 0.9911 - val_loss: 0.0516 - val_accuracy: 0.9856

Evaluar el modelo¶

Veremos ahora qué tan bien hizo el modelo en su fase de entrenamiento, viendo las grÔficas de entrenamiento tanto en pérdida como en precisión.

Gráficas de funciones de pérdida y accuracy¶

In [15]:
import matplotlib.pyplot as plt

# Del objeto history, podemos sacar la información guardada a traveś del entrenamiento
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1,len(acc)+1)

n_row = 1
n_col = 2
fig, ax = plt.subplots(n_row, n_col, sharex = False, sharey = False, figsize=(16,4))


ax[0].plot(epochs, acc, 'r', label='Training accuracy')
ax[0].plot(epochs, val_acc, 'b', label='Validation accuracy')
ax[0].legend(fontsize=12,loc=0)
ax[0].set_title('Training and Validation Accuracy',fontsize=16)
ax[0].set_ylabel('measure',fontsize=14)
ax[0].set_xlabel('epoch', fontsize = 14)
ax[0].set_xlim([1, len(acc)])

ax[1].plot(epochs, loss, 'r', label='Training Loss')
ax[1].plot(epochs, val_loss, 'b', label='Validation Loss')
ax[1].legend(fontsize=12)
ax[1].set_title('Training and Validation Loss',fontsize=16)
ax[1].set_ylabel('measure',fontsize=14)
ax[1].set_xlabel('epoch', fontsize = 14)
ax[1].set_xlim([1, len(acc)])

plt.show()

Evaluar el modelo con los dato de prueba (test)¶

In [16]:
model.evaluate(test_images,test_labels)
313/313 [==============================] - 0s 940us/step - loss: 0.0463 - accuracy: 0.9849
Out[16]:
[0.04629792645573616, 0.9848999977111816]

Guardar Modelo (Pesos + Diseño)¶

In [17]:
model.save('../Datos/model_MNIST.h5')
#model.save('/tmp/model_MNIST.h5')

Muestra de algunas predicciones¶

Calcula las clases predichas las probabilidades calculadas por softmax

In [18]:
preds = model.predict(test_images)
print(preds.shape)
(10000, 10)

Observemos que las predicciones vienen en forma de probabilidad:

In [19]:
#Elegir un elemento de test al azar
azar_test=np.random.randint(len(test_images))

#mostrar vector de probabilidades (resultado del softmax)
print(np.round(preds[azar_test],2))
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]

AsĆ­ pues, elegiremos el indice de la mayor probabilidad para elegir la etiqueta predicha:

In [20]:
# Calcular el ƭndice + mƔximo por filas
label_preds=np.argmax(preds,axis=1)
print("CuƔntos label predichos:",label_preds.shape,'\n')
print("Predicciones:\n")
print(label_preds)
CuƔntos label predichos: (10000,) 

Predicciones:

[7 2 1 ... 4 5 6]

En consecuencia, de nuestro elemento elegido al azar, podemos decir que la predicción es:

In [21]:
print("Etiqueta predicha:",label_preds[azar_test])
Etiqueta predicha: 4
In [22]:
print("MƔquina vs Humano\n")
plt.imshow(test_images[azar_test,:,:,0],cmap='binary')
#plt.axis('off')
plt.title('label humano: ' +str(test_labels[azar_test]),fontsize=14)
plt.xlabel("label mƔquina: "+str(label_preds[azar_test]),fontsize=14)
plt.xticks([], [])
plt.yticks([], [])
plt.show()
MƔquina vs Humano

In [25]:
azar_test= np.random.randint(len(bad_pred))
print("Mala Predicción:\n")

plt.title('Humano: ' +str(test_labels[bad_pred[azar_test]]),fontsize=16)
plt.imshow(test_images[bad_pred[azar_test],:,:,0],cmap='gray')
plt.xlabel("MƔquina: "+str(np.argmax(preds[bad_pred[azar_test]])),fontsize=14)
plt.show()
Mala Predicción:

MNIST Fashion¶

Hagamos el mismo proceso anterior, pero Ʃsta vez usando el conjunto de prendas MNIST Fashion.

Comenzamos cargando los datos:

Carga de Datos¶

In [3]:
# apunta  los datos
mnist_fashion = tf.keras.datasets.fashion_mnist

# lee los conjuntos de datos, los cuales vienen separados de antemano para entrenamiento y test
(training_images, training_labels), (test_images, test_labels) = mnist_fashion.load_data()

# Verificar forma de los datos
print("Forma de los datos de entrenamiento:",training_images.shape)
Forma de los datos de entrenamiento: (60000, 28, 28)

Pre-procesamiento¶

In [4]:
# reshape para colocar los datos de entrenamiento en el fomato apropiado.
# Agrega una dimensión al final y  normaliza los datos
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0

# reshape para colocar los datos de test en el fomato apropiado. Agrega una dimensión al final y  normaliza los datos
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images/255.0

print("Nueva forma de los datos de entrenamiento:", training_images.shape)
Nueva forma de los datos de entrenamiento: (60000, 28, 28, 1)

Etiquetas¶

No olvidemos que a pesar de tener etiquetas en forma de nĆŗmero en nuestro conjunto de datos, ellas corresponden a nombres de objetos.

No debemos perder ésta conexión, así que traemos la lista de nombres por aparte:

In [5]:
nombres_prendas = ['Camiseta/top', 'Pantalón', 'Jersey', 'Vestido', 'Abrigo',
               'Sandalia', 'Camisa', 'Tenis', 'Bolso', 'Botines']

Visualización¶

In [6]:
# muestra una imagen de entranamiento
azar=np.random.randint(len(training_images))
print("Datos en bruto:\n")
print(training_images[azar,10:15,10:15,0],'\n')


print("Imagen Asociada:\n")
plt.imshow(training_images[azar,:,:,0],cmap='binary')
plt.axis('off')
plt.title(str(nombres_prendas[training_labels[azar]]),fontsize=16)
plt.show()
Datos en bruto:

[[0.89019608 0.90196078 0.89411765 0.89803922 0.89803922]
 [0.89803922 0.90588235 0.90196078 0.89411765 0.89803922]
 [0.90196078 0.90588235 0.90196078 0.89411765 0.89803922]
 [0.90588235 0.90196078 0.90196078 0.89803922 0.90980392]
 [0.90196078 0.90196078 0.90196078 0.90196078 0.90980392]] 

Imagen Asociada:

In [7]:
#CuƔntas filas
filas=3
#Cuantas columnas
colus=4
#Elementos totales
n=filas*colus
#Elegir una muestra del dataset via Ć­ndices
vector_azar=np.random.randint(len(training_images),size=(n,))
# contador para dibujar en la grilla
w=1
#iniciar espacio de dibujo
plt.figure(figsize=(15,10))
#titulo
plt.suptitle("Ejemplos del dataset MNIST Fashion",fontsize=18)

# Loop anidado para recorrer la matriz completa
for i in range(filas):
    for j in range(colus):
        
        # subplots se peden contar incrementalmente
        plt.subplot(filas,colus,w)
        # dibujar el ejemplo de la muestra convertida a una matrix 28X28
        plt.imshow(training_images[vector_azar[w-1]].reshape((28, 28)), cmap="binary")
        #mostrar la etiqueta dada por el humano a dicho ejemplo (Aprendizaje supervisado)
        plt.title(nombres_prendas[training_labels[vector_azar[w-1]]],fontsize=16)
        #No mostrar ejes corrdenados
        plt.axis("off")
        # Incrementar contador
        w+=1

plt.show()
#mostrar Ć­ndices de los ejemplos elegidos
print("\nIndices Elegidos: ",vector_azar,"\n")
# mostrar etiquetas correspondientes
print("\nElementos Elegidos: ",training_labels[vector_azar],"\n")
Indices Elegidos:  [18907 43759 40151 18870 24053 57054 52309 18663 56167  6379 37429 37985] 


Elementos Elegidos:  [4 8 3 6 4 5 0 5 5 9 7 6] 

Definir el Modelo¶

  1. Capa 1: Conv2D con 64 filtros (kernels) de tamaño 3*3. Cada image viene en un tensor de tamaño 28 x 28 x 1. Los filtros son pasados por una f. de activación 'relu'.

  2. Capa 2. MaxPooling. Reduce cada filtro. Toma regiones secuenciales 2*2 y los reduce tomando el mÔximo de cada región. No usa f. de activación.

  3. Capa 1: Conv2D con 64 filtros (kernels) de tamaño 3*3. Cada image viene en un tensor de tamaño 28 x 28 x 1. Los filtros son pasados por una f. de activación 'relu'.

  4. Capa 2. MaxPooling. Reduce cada filtro. Toma regiones secuenciales 2*2 y los reduce tomando el mÔximo de cada región. No usa f. de activación.

  5. Capa 3. Flatten. Toma todos los filtros resultantes de la capa MaxPooling y los organiza como un Ćŗnico tensor unidimensional

  6. Capa 4. Dense. Recibe el tensor saliente de la capa Flatten y genera una salida en 128 unidades, usando activación relu

  7. Capa 5. Dense. Recibe el tensor unidmensional de tamaƱo 128 y lo transforma en la salida de 10 unidades. Hay 10 clases.

El predictor es al final transformado por la acticación softmax para obtener una distribución de la posible clase para la imagend e entrada

In [37]:
model = tf.keras.models.Sequential([
    ###Capas convolucionadas
    
    #Convolución 1
  tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), activation='relu', input_shape=(28, 28, 1)),
    #Pooling 1
  tf.keras.layers.MaxPooling2D(2, 2),
  tf.keras.layers.Dropout(0.4), 
    #Convolución 2
  tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    #Pooling 2
  tf.keras.layers.MaxPooling2D(2,2),
    
    ###Capas Densas
    # Aplanamiento
  tf.keras.layers.Flatten(),
    #Capa Densa
    tf.keras.layers.Dropout(0.4), 
    tf.keras.layers.Dense(128, activation='relu'),
    

    #Capa densa, clasificación
  tf.keras.layers.Dense(10, activation='softmax')
])

Es de Extremada importancia ver el diseƱo de la red para ver quƩ tantos parƔmetros tiene el modelo:

In [38]:
model.summary()
Model: "sequential_10"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_20 (Conv2D)          (None, 26, 26, 64)        640       
                                                                 
 max_pooling2d_20 (MaxPoolin  (None, 13, 13, 64)       0         
 g2D)                                                            
                                                                 
 dropout_6 (Dropout)         (None, 13, 13, 64)        0         
                                                                 
 conv2d_21 (Conv2D)          (None, 11, 11, 128)       73856     
                                                                 
 max_pooling2d_21 (MaxPoolin  (None, 5, 5, 128)        0         
 g2D)                                                            
                                                                 
 flatten_10 (Flatten)        (None, 3200)              0         
                                                                 
 dropout_7 (Dropout)         (None, 3200)              0         
                                                                 
 dense_20 (Dense)            (None, 128)               409728    
                                                                 
 dense_21 (Dense)            (None, 10)                1290      
                                                                 
=================================================================
Total params: 485,514
Trainable params: 485,514
Non-trainable params: 0
_________________________________________________________________

Crea una clase derivada de tf.keras.callbacks.Callback¶

Se usa para pasar funciones de control al algoritmo de estimación.

AquĆ­ la usaremos para el entrenamiento pare cuando se alcance un determinado accuracy con los datos de entrenamiento.

tf.keras.callbacks.Callback es una clase abstracta para permitir escribir mƩtodos que actuan en el proceso de entranamiento o de test. Para detalles vea tf.keras.callbacks.Callback.

In [39]:
class MNIST_Callback(tf.keras.callbacks.Callback):
    
    # mƩtodo dentro de la clase myCallback, heredada de la clase Callback de keras
    def on_epoch_end(self, epoch, logs={}):
        if(logs.get('val_accuracy')>=0.98):
            print("\nSe alcanzó un 99.9% de precisión en el entrenamiento! Cancelando Entrenamiento...")
            self.model.stop_training = True

# crea una instancia de clase
accu_callback = MNIST_Callback()

Observen como se pasan los callbacks

Compilar el modelo¶

In [40]:
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

Entrena el modelo¶

In [41]:
history = model.fit(training_images, training_labels, 
                    epochs=40, 
                    validation_split=0.2, 
                    batch_size=64,
                    callbacks=[accu_callback])
Epoch 1/40
750/750 [==============================] - 10s 13ms/step - loss: 0.5633 - accuracy: 0.7922 - val_loss: 0.3809 - val_accuracy: 0.8625
Epoch 2/40
750/750 [==============================] - 10s 13ms/step - loss: 0.3693 - accuracy: 0.8652 - val_loss: 0.3165 - val_accuracy: 0.8855
Epoch 3/40
750/750 [==============================] - 10s 13ms/step - loss: 0.3239 - accuracy: 0.8798 - val_loss: 0.3025 - val_accuracy: 0.8892
Epoch 4/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2977 - accuracy: 0.8907 - val_loss: 0.2790 - val_accuracy: 0.8982
Epoch 5/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2747 - accuracy: 0.8981 - val_loss: 0.2852 - val_accuracy: 0.8923
Epoch 6/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2577 - accuracy: 0.9037 - val_loss: 0.2528 - val_accuracy: 0.9077
Epoch 7/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2469 - accuracy: 0.9068 - val_loss: 0.2477 - val_accuracy: 0.9068
Epoch 8/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2337 - accuracy: 0.9121 - val_loss: 0.2565 - val_accuracy: 0.9043
Epoch 9/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2224 - accuracy: 0.9161 - val_loss: 0.2354 - val_accuracy: 0.9122
Epoch 10/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2139 - accuracy: 0.9188 - val_loss: 0.2447 - val_accuracy: 0.9076
Epoch 11/40
750/750 [==============================] - 10s 13ms/step - loss: 0.2031 - accuracy: 0.9247 - val_loss: 0.2305 - val_accuracy: 0.9132
Epoch 12/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1967 - accuracy: 0.9246 - val_loss: 0.2283 - val_accuracy: 0.9151
Epoch 13/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1875 - accuracy: 0.9279 - val_loss: 0.2251 - val_accuracy: 0.9180
Epoch 14/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1810 - accuracy: 0.9315 - val_loss: 0.2296 - val_accuracy: 0.9157
Epoch 15/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1797 - accuracy: 0.9315 - val_loss: 0.2234 - val_accuracy: 0.9194
Epoch 16/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1723 - accuracy: 0.9334 - val_loss: 0.2301 - val_accuracy: 0.9141
Epoch 17/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1642 - accuracy: 0.9375 - val_loss: 0.2310 - val_accuracy: 0.9153
Epoch 18/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1633 - accuracy: 0.9382 - val_loss: 0.2306 - val_accuracy: 0.9138
Epoch 19/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1567 - accuracy: 0.9403 - val_loss: 0.2546 - val_accuracy: 0.9037
Epoch 20/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1497 - accuracy: 0.9423 - val_loss: 0.2419 - val_accuracy: 0.9162
Epoch 21/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1491 - accuracy: 0.9421 - val_loss: 0.2253 - val_accuracy: 0.9189
Epoch 22/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1466 - accuracy: 0.9431 - val_loss: 0.2425 - val_accuracy: 0.9164
Epoch 23/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1411 - accuracy: 0.9470 - val_loss: 0.2301 - val_accuracy: 0.9200
Epoch 24/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1405 - accuracy: 0.9469 - val_loss: 0.2353 - val_accuracy: 0.9168
Epoch 25/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1367 - accuracy: 0.9483 - val_loss: 0.2411 - val_accuracy: 0.9175
Epoch 26/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1334 - accuracy: 0.9490 - val_loss: 0.2446 - val_accuracy: 0.9182
Epoch 27/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1322 - accuracy: 0.9491 - val_loss: 0.2270 - val_accuracy: 0.9228
Epoch 28/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1252 - accuracy: 0.9518 - val_loss: 0.2465 - val_accuracy: 0.9187
Epoch 29/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1272 - accuracy: 0.9514 - val_loss: 0.2500 - val_accuracy: 0.9163
Epoch 30/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1254 - accuracy: 0.9530 - val_loss: 0.2384 - val_accuracy: 0.9184
Epoch 31/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1222 - accuracy: 0.9534 - val_loss: 0.2401 - val_accuracy: 0.9171
Epoch 32/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1201 - accuracy: 0.9541 - val_loss: 0.2520 - val_accuracy: 0.9153
Epoch 33/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1164 - accuracy: 0.9551 - val_loss: 0.2413 - val_accuracy: 0.9183
Epoch 34/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1178 - accuracy: 0.9554 - val_loss: 0.2522 - val_accuracy: 0.9227
Epoch 35/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1118 - accuracy: 0.9569 - val_loss: 0.2459 - val_accuracy: 0.9186
Epoch 36/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1123 - accuracy: 0.9575 - val_loss: 0.2719 - val_accuracy: 0.9151
Epoch 37/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1127 - accuracy: 0.9579 - val_loss: 0.2580 - val_accuracy: 0.9187
Epoch 38/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1118 - accuracy: 0.9565 - val_loss: 0.2499 - val_accuracy: 0.9207
Epoch 39/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1086 - accuracy: 0.9582 - val_loss: 0.2553 - val_accuracy: 0.9201
Epoch 40/40
750/750 [==============================] - 10s 13ms/step - loss: 0.1082 - accuracy: 0.9600 - val_loss: 0.2522 - val_accuracy: 0.9216

Evaluar el modelo¶

Veremos ahora qué tan bien hizo el modelo en su fase de entrenamiento, viendo las grÔficas de entrenamiento tanto en pérdida como en precisión.

In [42]:
model.evaluate(test_images,test_labels)
313/313 [==============================] - 1s 2ms/step - loss: 0.2701 - accuracy: 0.9185
Out[42]:
[0.2700694501399994, 0.9185000061988831]

Guardar Modelo (Pesos + Diseño)¶

In [43]:
model.save('../Datos/model_MNIST_Fashion.h5')

Gráficas de funciones de pérdida y accuracy¶

In [44]:
import matplotlib.pyplot as plt

# Del objeto history, podemos sacar la información guardada a traveś del entrenamiento
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

n_row = 1
n_col = 2
fig, ax = plt.subplots(n_row, n_col, sharex = False, sharey = False, figsize=(16,4))


ax[0].plot(epochs, acc, 'r', label='Training accuracy')
ax[0].plot(epochs, val_acc, 'b', label='Validation accuracy')
ax[0].legend(fontsize=12,loc=0)
ax[0].set_title('Training and Validation Accuracy',fontsize=16)
ax[0].set_ylabel('measure',fontsize=14)
ax[0].set_xlabel('epoch', fontsize = 14)
ax[0].set_xlim([1, len(acc)])

ax[1].plot(epochs, loss, 'r', label='Training Loss')
ax[1].plot(epochs, val_loss, 'b', label='Validation Loss')
ax[1].legend(fontsize=12)
ax[1].set_title('Training and Validation Loss',fontsize=16)
ax[1].set_ylabel('measure',fontsize=14)
ax[1].set_xlabel('epoch', fontsize = 14)
ax[1].set_xlim([1, len(acc)])


plt.show()

Muestra de algunas predicciones¶

Calcula las clases predichas las probabilidades calculadas por softmax

In [45]:
preds = model.predict(test_images)
print(preds.shape)  
(10000, 10)

Observemos que las predicciones vienen en forma de probabilidad:

In [46]:
#Elegir un elemento de test al azar
azar_test=np.random.randint(len(test_images))

#mostrar vecto de probabilidades (resultado del softmax)
print(np.round(preds[azar_test],2))
[0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]

AsĆ­ pues, elegiremos el indice de la mayor probabilidad para elegir la etiqueta predicha:

In [47]:
# Calcular el ƭnidce mƔximo por filas
label_preds=np.argmax(preds,axis=1)
print("Cuantos label predichos:",label_preds.shape,'\n')
print("Predicciones:\n")
print(label_preds)
Cuantos label predichos: (10000,) 

Predicciones:

[9 2 1 ... 8 1 5]

Así pues, de nuestro elemento elegido al azar, podemos decir que la predicción es:

In [48]:
print("Etiqueta predicha:",label_preds[azar_test])
print("Prenda   predicha:",nombres_prendas[label_preds[azar_test]])
Etiqueta predicha: 1
Prenda   predicha: Pantalón
In [49]:
print("MƔquina vs Humano:\n")
plt.imshow(test_images[azar_test,:,:,0],cmap='binary')
#plt.axis('off')
plt.title('Humano: ' + nombres_prendas[test_labels[azar_test]],fontsize=14)
plt.xlabel("MƔquina: "+ nombres_prendas[label_preds[azar_test]],fontsize=14)
plt.xticks([], [])
plt.yticks([], [])
plt.show()
MƔquina vs Humano:

Detección de malas predicciones¶

In [50]:
bad_pred=[]
for i in range (len(label_preds)):
    if label_preds[i]!=test_labels[i]:
        bad_pred.append(i)

bad_pred=np.array(bad_pred)
In [ ]:
print(bad_pred)
print("\nCuƔntas:",bad_pred.shape[0])
[  23   25   42   49   57   67   68   98  147  150  244  247  248  312
  316  324  378  379  381  382  389  395  441  444  455  457  460  468
  474  476  491  510  525  526  572  585  607  628  639  669  670  674
  688  706  711  713  724  732  738  753  760  787  851  877  881  890
  894  905  909  910  925  930  935  938  956  960  965  966  976  977
  979  985  997 1000 1004 1005 1025 1029 1101 1104 1107 1111 1125 1139
 1140 1142 1160 1162 1165 1174 1192 1194 1197 1210 1223 1224 1231 1234
 1236 1280 1286 1293 1300 1305 1312 1326 1329 1335 1336 1342 1374 1385
 1388 1399 1408 1425 1450 1462 1469 1471 1496 1501 1509 1522 1528 1533
 1572 1585 1602 1617 1620 1622 1626 1632 1642 1643 1650 1665 1679 1684
 1712 1739 1743 1744 1746 1777 1778 1810 1826 1836 1852 1856 1861 1867
 1879 1900 1922 1942 1943 1953 1964 1968 1980 2001 2006 2022 2037 2062
 2067 2069 2071 2082 2097 2104 2106 2110 2144 2162 2189 2191 2195 2236
 2239 2245 2252 2256 2278 2281 2290 2302 2309 2311 2318 2319 2326 2343
 2351 2352 2367 2397 2425 2431 2435 2455 2457 2464 2469 2485 2487 2506
 2507 2509 2527 2540 2548 2551 2571 2575 2580 2588 2599 2603 2619 2628
 2629 2652 2653 2661 2670 2678 2681 2684 2689 2701 2717 2721 2732 2737
 2741 2746 2760 2764 2779 2787 2814 2817 2839 2840 2842 2843 2856 2897
 2898 2900 2905 2909 2914 2918 2919 2920 2934 2942 2951 2953 2965 2967
 2973 2979 2985 2986 2991 2997 3001 3008 3015 3019 3038 3058 3082 3084
 3101 3103 3116 3123 3132 3174 3181 3188 3198 3203 3205 3209 3220 3229
 3232 3240 3241 3244 3258 3262 3282 3284 3304 3313 3322 3323 3338 3342
 3370 3386 3401 3436 3439 3451 3458 3466 3468 3484 3488 3489 3491 3496
 3497 3499 3507 3531 3532 3535 3540 3552 3553 3554 3572 3585 3588 3609
 3613 3625 3626 3639 3640 3643 3649 3669 3671 3673 3681 3706 3730 3731
 3741 3760 3765 3772 3787 3800 3804 3805 3809 3816 3829 3830 3842 3861
 3864 3865 3871 3880 3881 3909 3914 3937 3938 3940 3941 3953 3954 3974
 3999 4025 4041 4056 4061 4065 4067 4071 4079 4082 4084 4102 4106 4108
 4109 4121 4127 4140 4142 4143 4148 4153 4159 4166 4192 4193 4224 4231
 4233 4245 4251 4271 4272 4280 4299 4307 4317 4333 4337 4404 4405 4411
 4416 4422 4433 4460 4462 4471 4526 4568 4569 4608 4639 4664 4668 4672
 4692 4693 4705 4711 4724 4727 4742 4746 4751 4764 4782 4784 4803 4817
 4823 4828 4829 4836 4850 4852 4880 4886 4896 4917 4922 4924 4934 4941
 4995 5006 5009 5014 5032 5041 5052 5066 5069 5070 5077 5101 5108 5123
 5129 5148 5155 5167 5173 5178 5184 5186 5197 5210 5228 5231 5248 5249
 5255 5259 5260 5285 5297 5316 5334 5336 5338 5375 5381 5410 5415 5424
 5452 5464 5468 5473 5497 5510 5511 5512 5520 5522 5530 5533 5566 5569
 5576 5587 5589 5594 5601 5610 5623 5648 5654 5655 5661 5672 5674 5679
 5689 5695 5701 5713 5718 5719 5757 5777 5806 5820 5826 5849 5899 5927
 5938 5946 5966 5971 5987 6008 6012 6024 6037 6061 6065 6077 6086 6094
 6096 6103 6127 6129 6147 6159 6160 6162 6168 6169 6175 6201 6205 6207
 6211 6225 6230 6231 6254 6258 6280 6293 6331 6335 6344 6356 6363 6365
 6395 6405 6407 6418 6433 6437 6441 6444 6453 6463 6464 6472 6474 6514
 6539 6564 6566 6575 6593 6596 6625 6626 6629 6654 6655 6665 6676 6679
 6688 6689 6700 6710 6721 6727 6733 6737 6751 6752 6762 6774 6797 6799
 6801 6809 6822 6826 6844 6855 6861 6866 6868 6874 6899 6908 6926 6928
 6940 6958 6984 7013 7024 7026 7028 7030 7040 7047 7049 7068 7073 7103
 7109 7125 7130 7134 7138 7165 7167 7182 7188 7189 7190 7195 7228 7233
 7249 7258 7265 7278 7307 7314 7315 7332 7343 7349 7369 7376 7393 7405
 7416 7424 7442 7472 7476 7518 7526 7555 7584 7596 7613 7635 7654 7660
 7679 7683 7714 7755 7761 7769 7778 7779 7800 7818 7847 7868 7876 7899
 7905 7906 7914 7924 7936 7941 7945 7948 7965 7974 7976 7981 7983 7986
 7998 8007 8031 8051 8054 8059 8069 8079 8085 8121 8154 8156 8205 8217
 8226 8259 8260 8268 8283 8292 8296 8324 8348 8373 8374 8375 8406 8415
 8425 8457 8463 8525 8532 8538 8559 8568 8569 8592 8598 8611 8617 8621
 8633 8640 8645 8646 8658 8664 8669 8688 8693 8705 8706 8714 8716 8717
 8725 8728 8745 8757 8763 8764 8804 8818 8826 8832 8834 8877 8879 8888
 8892 8914 8919 8933 8939 8940 8949 8952 8958 9017 9032 9061 9062 9074
 9086 9087 9094 9095 9100 9117 9131 9133 9149 9152 9154 9157 9165 9183
 9197 9198 9210 9211 9212 9218 9235 9237 9238 9244 9247 9251 9260 9263
 9291 9306 9313 9320 9325 9334 9342 9344 9347 9349 9355 9375 9398 9402
 9405 9441 9445 9485 9502 9524 9531 9537 9567 9573 9577 9580 9597 9601
 9645 9662 9687 9690 9692 9701 9705 9719 9743 9748 9791 9795 9835 9856
 9857 9867 9876 9880 9897 9917 9919 9945 9947 9951 9953 9955 9961 9963
 9972 9977 9981 9989 9991]

CuƔntas: 901
In [51]:
azar_test= np.random.randint(len(bad_pred))
print("Mala Predicción:\n")

plt.title('Humano: ' +nombres_prendas[test_labels[bad_pred[azar_test]]],fontsize=16)
plt.imshow(test_images[bad_pred[azar_test],:,:,0],cmap='gray')
plt.xlabel("MƔquina: "+nombres_prendas[np.argmax(preds[bad_pred[azar_test]])],fontsize=14)
plt.show()
Mala Predicción:

Matriz de Confusión¶

In [52]:
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.metrics import plot_confusion_matrix

print('Confusion Matrix:\n')
print(confusion_matrix(test_labels, label_preds),'\n')

print(classification_report(test_labels, label_preds))
Confusion Matrix:

[[867   0  24  15   3   2  82   1   6   0]
 [  1 978   0  14   3   0   2   0   2   0]
 [ 13   0 883   9  39   0  56   0   0   0]
 [ 11   2   9 933  25   0  19   0   1   0]
 [  1   0  42  23 874   0  58   0   2   0]
 [  0   0   0   0   0 977   0  16   0   7]
 [105   1  64  21  47   0 753   0   9   0]
 [  0   0   0   0   0   6   0 974   0  20]
 [  3   0   3   5   1   0   3   3 981   1]
 [  0   0   0   0   0   3   0  31   1 965]] 

              precision    recall  f1-score   support

           0       0.87      0.87      0.87      1000
           1       1.00      0.98      0.99      1000
           2       0.86      0.88      0.87      1000
           3       0.91      0.93      0.92      1000
           4       0.88      0.87      0.88      1000
           5       0.99      0.98      0.98      1000
           6       0.77      0.75      0.76      1000
           7       0.95      0.97      0.96      1000
           8       0.98      0.98      0.98      1000
           9       0.97      0.96      0.97      1000

    accuracy                           0.92     10000
   macro avg       0.92      0.92      0.92     10000
weighted avg       0.92      0.92      0.92     10000

In [ ]:
print(nombres_prendas)
['Camiseta/top', 'Pantalón', 'Jersey', 'Vestido', 'Abrigo', 'Sandalia', 'Camisa', 'Tenis', 'Bolso', 'Botines']

Visualizando Convoluciones¶

In [53]:
f, axarr = plt.subplots(3,5,figsize=(18,12))

FIRST_IMAGE=np.random.randint(len(test_images))
SECOND_IMAGE=np.random.randint(len(test_images))
THIRD_IMAGE=np.random.randint(len(test_images))
CONVOLUTION_NUMBER=1


from tensorflow.keras import models


layer_outputs = [layer.output for layer in model.layers]

activation_model = tf.keras.models.Model(inputs = model.input, outputs = layer_outputs)


#Originals

axarr[0,0].imshow(test_images[FIRST_IMAGE].reshape(28,28),cmap='inferno')
axarr[1,0].imshow(test_images[SECOND_IMAGE].reshape(28,28),cmap='inferno')
axarr[2,0].imshow(test_images[THIRD_IMAGE].reshape(28,28),cmap='inferno')

# Convoluciones

for x in range(0,4):
  # Primera Imagen
    f1 = activation_model.predict(test_images[FIRST_IMAGE].reshape(1, 28, 28, 1))[x]
    axarr[0,x+1].imshow(f1[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
    axarr[0,x+1].grid(False)
  # Segunda Imagen
    f2 = activation_model.predict(test_images[SECOND_IMAGE].reshape(1, 28, 28, 1))[x]
    axarr[1,x+1].imshow(f2[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
    axarr[1,x+1].grid(False)
  # Tercera Imagen
    f3 = activation_model.predict(test_images[THIRD_IMAGE].reshape(1, 28, 28, 1))[x]
    axarr[2,x+1].imshow(f3[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
    axarr[2,x+1].grid(False)

[Volver al Inicio]

Dogs vs. Cats ¶

Hay un conjunto muy famoso en la historia de la visión por computador y los ciber ataques:

Dogs Vs. Cats

"Originalmente, esto fue un desafío en la construcción de un clasificador dirigido a los mejores profesionales de aprendizaje automÔtico e inteligencia artificial del mundo, pero la tecnología ha avanzado tan rÔpido que verÔ cómo puede hacerlo en solo unos minutos con una simple programación de red neuronal convolucional." -Lawrence Moroney.

Cabe resaltar lo siguiente:

Los conjuntos de juguete de MNIST/Fashion contenƭan imƔgenes del mismo tamaƱo y estaban a escala de grises.

Esto se aleja un poco de la vida real, asƭ que ahora enfrentaremos un problema mƔs difƭcil.

Un problema donde las imƔgenes vengan en todos los tamaƱos y en todos los colores :)

AsĆ­ que, como primera instancia, tendremos que hacer un pre-procesamiento de los datos.

Por ejemplo, colocaremos todas las imƔgenes del mismo tamaƱo (escalamiento).

Seguiremos los siguientes pasos:

  1. Explorar el conjunto de datos.
  2. Construir y Entrenar una red neuronal que reconozca la diferencia entre los dos.
  3. Evaluar la precisión de Entrenamiento y Validación.

ADVERTENCIA: Este ejercicio puede ser muy pesado para su computador personal. Considere usar Colaboratory

Explorando los Datos¶

La siguiente prƔctica la haremos en Colaboratory.

Si desea hacerlo de manera local, le recomendamos usar las rutas de ficheros apropiadas para su sistema operativo.

Para este ejemplo, se usaraƔ una base filtrada de 2000 imƔgenes.

In [54]:
!wget --no-check-certificate \
  https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip \
  -O /tmp/cats_and_dogs_filtered.zip
--2021-11-12 11:38:52--  https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip
Resolving storage.googleapis.com (storage.googleapis.com)... 142.250.78.176, 172.217.28.112, 172.217.30.208, ...
Connecting to storage.googleapis.com (storage.googleapis.com)|142.250.78.176|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 68606236 (65M) [application/zip]
Saving to: ā€˜/tmp/cats_and_dogs_filtered.zip’

/tmp/cats_and_dogs_ 100%[===================>]  65.43M  24.0MB/s    in 2.7s    

2021-11-12 11:38:55 (24.0 MB/s) - ā€˜/tmp/cats_and_dogs_filtered.zip’ saved [68606236/68606236]

Descomprimiendo Datos¶

In [6]:
import os
import zipfile

local_zip = '/tmp/cats_and_dogs_filtered.zip'

zip_ref = zipfile.ZipFile(local_zip, 'r')

zip_ref.extractall('/tmp')
zip_ref.close()
In [7]:
base_dir = '/tmp/cats_and_dogs_filtered'

train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')

# Directory with our training cat/dog pictures
train_cats_dir = os.path.join(train_dir, 'cats')
train_dogs_dir = os.path.join(train_dir, 'dogs')

# Directory with our validation cat/dog pictures
validation_cats_dir = os.path.join(validation_dir, 'cats')
validation_dogs_dir = os.path.join(validation_dir, 'dogs')

Generando listas de nombres¶

In [8]:
train_cat_fnames = os.listdir( train_cats_dir )
train_dog_fnames = os.listdir( train_dogs_dir )

print(train_cat_fnames[:10])
print(train_dog_fnames[:10])
['cat.289.jpg', 'cat.428.jpg', 'cat.724.jpg', 'cat.185.jpg', 'cat.507.jpg', 'cat.950.jpg', 'cat.61.jpg', 'cat.202.jpg', 'cat.875.jpg', 'cat.521.jpg']
['dog.525.jpg', 'dog.985.jpg', 'dog.176.jpg', 'dog.467.jpg', 'dog.608.jpg', 'dog.53.jpg', 'dog.532.jpg', 'dog.338.jpg', 'dog.837.jpg', 'dog.201.jpg']

Verificando cantidades de Datos¶

In [9]:
print('total training cat images :', len(os.listdir(train_cats_dir)))
print('total training dog images :', len(os.listdir(train_dogs_dir)),'\n')

print('total validation cat images :', len(os.listdir(validation_cats_dir)))
print('total validation dog images :', len(os.listdir(validation_dogs_dir)))
total training cat images : 1000
total training dog images : 1000 

total validation cat images : 500
total validation dog images : 500

Visualizando algunos Ejemplos¶

In [10]:
import matplotlib.image as mpimg
import matplotlib.pyplot as plt

# Malla de imagenes 4x4
nrows = 4
ncols = 4

# Indice aleatorio para iterar sobre las imagenes
pic_index = np.random.randint(len(os.listdir(train_cats_dir))-8) 

# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols*4, nrows*4)

# Tomar hilera de 8 desde Ć­ndice elegido
pic_index+=8

next_cat_pix = [os.path.join(train_cats_dir, fname) 
                for fname in train_cat_fnames[ pic_index-8:pic_index] 
               ]

next_dog_pix = [os.path.join(train_dogs_dir, fname) 
                for fname in train_dog_fnames[ pic_index-8:pic_index]
               ]

for i, img_path in enumerate(next_cat_pix+next_dog_pix):
    # Set up subplot; subplot indices start at 1
    sp = plt.subplot(nrows, ncols, i + 1)
    sp.axis('Off') # Don't show axes (or gridlines)

    img = mpimg.imread(img_path)
    plt.imshow(img)

plt.show()

Diseñando Red Neuronal¶

In [17]:
model = tf.keras.models.Sequential([
    # Note the input shape is the desired size of the image 150x150 with 3 bytes color
    tf.keras.layers.Conv2D(8, (3,3), activation='relu', input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Dropout(0.4),
    tf.keras.layers.Conv2D(16, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2), 
    tf.keras.layers.Dropout(0.4),
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'), 
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Dropout(0.4),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(), 
    # 512 neuron hidden layer
    tf.keras.layers.Dense(64, activation='relu'), 
    tf.keras.layers.Dropout(0.4),
    # Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('cats') and 1 for the other ('dogs')
    tf.keras.layers.Dense(1, activation='sigmoid')  
])

Veamos un resumen de la red para ver el número de parÔmetros y estructura.

In [18]:
model.summary()
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_3 (Conv2D)           (None, 148, 148, 8)       224       
                                                                 
 max_pooling2d_3 (MaxPooling  (None, 74, 74, 8)        0         
 2D)                                                             
                                                                 
 dropout (Dropout)           (None, 74, 74, 8)         0         
                                                                 
 conv2d_4 (Conv2D)           (None, 72, 72, 16)        1168      
                                                                 
 max_pooling2d_4 (MaxPooling  (None, 36, 36, 16)       0         
 2D)                                                             
                                                                 
 dropout_1 (Dropout)         (None, 36, 36, 16)        0         
                                                                 
 conv2d_5 (Conv2D)           (None, 34, 34, 32)        4640      
                                                                 
 max_pooling2d_5 (MaxPooling  (None, 17, 17, 32)       0         
 2D)                                                             
                                                                 
 dropout_2 (Dropout)         (None, 17, 17, 32)        0         
                                                                 
 flatten_1 (Flatten)         (None, 9248)              0         
                                                                 
 dense_2 (Dense)             (None, 64)                591936    
                                                                 
 dropout_3 (Dropout)         (None, 64)                0         
                                                                 
 dense_3 (Dense)             (None, 1)                 65        
                                                                 
=================================================================
Total params: 598,033
Trainable params: 598,033
Non-trainable params: 0
_________________________________________________________________

Compilar Modelo¶

In [19]:
from tensorflow.keras.optimizers import Adam

model.compile(optimizer=Adam(),
              loss='binary_crossentropy',
              metrics = ['accuracy'])

Generador de Imagenes para el entrenamiento¶

En este punto observaremos algo nuevo.

Como tenemos muchos datos, y serƭa muy pesado para el computador tenerlos en memoria, generaremos un apuntador a los directorios que contienen las imƔgenes e iremos leyendolas a medida que se va entrenando la red.

Estos apuntadores se conocen como ImageDataGenerator.

Son herramientas muy útiles, porque ademÔs permiten aumentar el número de datos de manera artificial y por ejemplo, escalar los datos a un mismo tamaño.

Los invitamos a revisar sus parƔmetros opcionales, se sorprenderƔn.

In [15]:
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# Normalizar Datos
train_datagen = ImageDataGenerator(rescale = 1.0/255.)
test_datagen  = ImageDataGenerator(rescale = 1.0/255.)

# --------------------
# Flujo de imagenes de entrenamiento en grupos de 20, escalando a 150x150 usando train_datagen generator
# --------------------
train_generator = train_datagen.flow_from_directory(train_dir,
                                                    batch_size=20,
                                                    class_mode='binary',
                                                    target_size=(150, 150))     
# --------------------
# Flujo de imagenes de validación en grupos de 20, escalando a 150x150 usando test_datagen generator
# --------------------
validation_generator =  test_datagen.flow_from_directory(validation_dir,
                                                         batch_size=20,
                                                         class_mode  = 'binary',
                                                         target_size = (150, 150))
Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.

Para mƔs opciones del generador, puedes ir aquƭ

Entrenar Modelo de Red Neuronal Convolucional¶

In [21]:
history = model.fit(train_generator,
                              validation_data=validation_generator,
                              steps_per_epoch=100,
                              epochs=50,
                              validation_steps=50,
                              verbose=1)
Epoch 1/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1895 - accuracy: 0.9200 - val_loss: 0.8626 - val_accuracy: 0.7060
Epoch 2/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1674 - accuracy: 0.9215 - val_loss: 0.9610 - val_accuracy: 0.7120
Epoch 3/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1586 - accuracy: 0.9280 - val_loss: 0.8823 - val_accuracy: 0.7170
Epoch 4/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1466 - accuracy: 0.9300 - val_loss: 0.9580 - val_accuracy: 0.7130
Epoch 5/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1442 - accuracy: 0.9415 - val_loss: 0.9743 - val_accuracy: 0.6970
Epoch 6/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1583 - accuracy: 0.9420 - val_loss: 0.8902 - val_accuracy: 0.7060
Epoch 7/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1583 - accuracy: 0.9365 - val_loss: 0.9257 - val_accuracy: 0.7200
Epoch 8/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1453 - accuracy: 0.9355 - val_loss: 0.9943 - val_accuracy: 0.7040
Epoch 9/50
100/100 [==============================] - 5s 50ms/step - loss: 0.1711 - accuracy: 0.9295 - val_loss: 0.9187 - val_accuracy: 0.7020
Epoch 10/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1438 - accuracy: 0.9435 - val_loss: 0.9834 - val_accuracy: 0.7240
Epoch 11/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1449 - accuracy: 0.9420 - val_loss: 0.9258 - val_accuracy: 0.7120
Epoch 12/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1303 - accuracy: 0.9420 - val_loss: 0.9820 - val_accuracy: 0.7180
Epoch 13/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1508 - accuracy: 0.9425 - val_loss: 0.9774 - val_accuracy: 0.6830
Epoch 14/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1333 - accuracy: 0.9400 - val_loss: 0.9077 - val_accuracy: 0.7240
Epoch 15/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1292 - accuracy: 0.9425 - val_loss: 0.9184 - val_accuracy: 0.7040
Epoch 16/50
100/100 [==============================] - 5s 51ms/step - loss: 0.1568 - accuracy: 0.9285 - val_loss: 0.8712 - val_accuracy: 0.7250
Epoch 17/50
100/100 [==============================] - 5s 54ms/step - loss: 0.1538 - accuracy: 0.9335 - val_loss: 0.9704 - val_accuracy: 0.7230
Epoch 18/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1363 - accuracy: 0.9475 - val_loss: 1.0407 - val_accuracy: 0.6990
Epoch 19/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1270 - accuracy: 0.9495 - val_loss: 0.8955 - val_accuracy: 0.7240
Epoch 20/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1194 - accuracy: 0.9510 - val_loss: 1.0690 - val_accuracy: 0.7210
Epoch 21/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1229 - accuracy: 0.9495 - val_loss: 0.9434 - val_accuracy: 0.7280
Epoch 22/50
100/100 [==============================] - 5s 51ms/step - loss: 0.1253 - accuracy: 0.9520 - val_loss: 0.9147 - val_accuracy: 0.7330
Epoch 23/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1178 - accuracy: 0.9490 - val_loss: 0.9697 - val_accuracy: 0.7210
Epoch 24/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1227 - accuracy: 0.9490 - val_loss: 0.9946 - val_accuracy: 0.7110
Epoch 25/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1291 - accuracy: 0.9470 - val_loss: 0.9687 - val_accuracy: 0.7160
Epoch 26/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1169 - accuracy: 0.9505 - val_loss: 0.9715 - val_accuracy: 0.7330
Epoch 27/50
100/100 [==============================] - 5s 51ms/step - loss: 0.1209 - accuracy: 0.9490 - val_loss: 1.0349 - val_accuracy: 0.7280
Epoch 28/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1162 - accuracy: 0.9545 - val_loss: 0.9865 - val_accuracy: 0.7110
Epoch 29/50
100/100 [==============================] - 5s 51ms/step - loss: 0.1184 - accuracy: 0.9560 - val_loss: 1.0008 - val_accuracy: 0.7170
Epoch 30/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1207 - accuracy: 0.9490 - val_loss: 0.9439 - val_accuracy: 0.7210
Epoch 31/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1059 - accuracy: 0.9580 - val_loss: 1.0793 - val_accuracy: 0.7080
Epoch 32/50
100/100 [==============================] - 5s 50ms/step - loss: 0.1297 - accuracy: 0.9480 - val_loss: 0.9164 - val_accuracy: 0.7020
Epoch 33/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1360 - accuracy: 0.9465 - val_loss: 1.0024 - val_accuracy: 0.7180
Epoch 34/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1073 - accuracy: 0.9605 - val_loss: 1.2116 - val_accuracy: 0.7210
Epoch 35/50
100/100 [==============================] - 5s 52ms/step - loss: 0.0965 - accuracy: 0.9605 - val_loss: 1.0551 - val_accuracy: 0.7170
Epoch 36/50
100/100 [==============================] - 5s 51ms/step - loss: 0.1060 - accuracy: 0.9505 - val_loss: 1.0071 - val_accuracy: 0.7040
Epoch 37/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1137 - accuracy: 0.9510 - val_loss: 1.0026 - val_accuracy: 0.7040
Epoch 38/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1013 - accuracy: 0.9610 - val_loss: 1.1187 - val_accuracy: 0.7120
Epoch 39/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1040 - accuracy: 0.9560 - val_loss: 0.9810 - val_accuracy: 0.7180
Epoch 40/50
100/100 [==============================] - 5s 51ms/step - loss: 0.0843 - accuracy: 0.9630 - val_loss: 1.1236 - val_accuracy: 0.7150
Epoch 41/50
100/100 [==============================] - 5s 52ms/step - loss: 0.0930 - accuracy: 0.9555 - val_loss: 1.1155 - val_accuracy: 0.7260
Epoch 42/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1090 - accuracy: 0.9550 - val_loss: 1.0117 - val_accuracy: 0.7080
Epoch 43/50
100/100 [==============================] - 5s 53ms/step - loss: 0.0920 - accuracy: 0.9615 - val_loss: 1.0925 - val_accuracy: 0.7030
Epoch 44/50
100/100 [==============================] - 5s 53ms/step - loss: 0.0943 - accuracy: 0.9620 - val_loss: 1.1371 - val_accuracy: 0.6990
Epoch 45/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1127 - accuracy: 0.9520 - val_loss: 1.0863 - val_accuracy: 0.7240
Epoch 46/50
100/100 [==============================] - 5s 52ms/step - loss: 0.0976 - accuracy: 0.9570 - val_loss: 1.0503 - val_accuracy: 0.7240
Epoch 47/50
100/100 [==============================] - 5s 52ms/step - loss: 0.1073 - accuracy: 0.9530 - val_loss: 0.9961 - val_accuracy: 0.7080
Epoch 48/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1030 - accuracy: 0.9555 - val_loss: 1.1035 - val_accuracy: 0.7180
Epoch 49/50
100/100 [==============================] - 5s 53ms/step - loss: 0.0954 - accuracy: 0.9655 - val_loss: 1.1259 - val_accuracy: 0.7170
Epoch 50/50
100/100 [==============================] - 5s 53ms/step - loss: 0.1039 - accuracy: 0.9610 - val_loss: 1.0636 - val_accuracy: 0.7270
In [22]:
model.save('../Datos/Cats_v_Dogs.h5')
In [ ]:
model=tf.keras.models.load_model('Cats_v_Dogs.h5')

Haciendo uso del Modelo (Sólo funciona en Colab)¶

In [ ]:
import numpy as np

from google.colab import files
from keras.preprocessing import image

#Cargar imagen desde Colab
uploaded=files.upload()

for fn in uploaded.keys():
 
    # Cargar imagen
    path='/content/' + fn
    img=image.load_img(path, target_size=(150, 150))
    
    #Preprocesar Imagen
    x=image.img_to_array(img)
    x=np.expand_dims(x, axis=0)
    images = np.vstack([x])
    
    # Usar Modelo (Predecir Imagen)
    classes = model.predict(images, batch_size=10)
    # Mostrar resultados
    print(classes)
    #Clasificar
    if classes[0]>0:
      print(fn + " Es un Perro")

    else:
      print(fn + " Es un Gato")
Upload widget is only available when the cell has been executed in the current browser session. Please rerun this cell to enable.

Haciendo uso local del modelo¶

In [52]:
from keras.preprocessing import image

#Cargar imagen desde un archivo local

path ='../Imagenes/'
files = ['Mila.jpg', 'Zeus.jpg']
size = 150

x = []

print('Mis gatos')

for i, file in enumerate(files):
    img=image.load_img(path+file, target_size=(size, size))
    sp = plt.subplot(1, 2, i + 1)
    sp.axis('Off') 
    plt.imshow(img)
    
    array = np.reshape(image.img_to_array(img), newshape =(1,size,size,3))
    x.append(array)    

images = np.vstack(x)
print('tamano del tensor', images.shape)
Mis gatos
tamano del tensor (2, 150, 150, 3)
In [47]:
classes = model.predict(images, batch_size=2)
# Mostrar resultados
print(classes)
    
for i, fn in enumerate(files):
    #Clasificar
    if classes[i]>0:
        print(fn + " Es un Perro")

    else:
        print(fn + " Es un Gato")
[[1.]
 [0.]]
Mila.jpg Es un Perro
Zeus.jpg Es un Gato

Visualizando Representaciones Intermedias¶

In [53]:
import numpy as np
import random
from   tensorflow.keras.preprocessing.image import img_to_array, load_img

# Let's define a new Model that will take an image as input, and will output
# intermediate representations for all layers in the previous model after
# the first.
successive_outputs = [layer.output for layer in model.layers[:-3]]

#visualization_model = Model(img_input, successive_outputs)
visualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs)

# Let's prepare a random input image of a cat or dog from the training set.
cat_img_files = [os.path.join(train_cats_dir, f) for f in train_cat_fnames]
dog_img_files = [os.path.join(train_dogs_dir, f) for f in train_dog_fnames]

img_path = random.choice(cat_img_files + dog_img_files)
img = load_img(img_path, target_size=(150, 150))  # this is a PIL image

x   = img_to_array(img)                           # Numpy array with shape (150, 150, 3)
x   = x.reshape((1,) + x.shape)                   # Numpy array with shape (1, 150, 150, 3)

# Rescale by 1/255
x /= 255.0

# Let's run our image through our network, thus obtaining all
# intermediate representations for this image.
successive_feature_maps = visualization_model.predict(x)

# These are the names of the layers, so can have them as part of our plot
layer_names = [layer.name for layer in model.layers]

# Mostrar Imagen Original
plt.figure()
plt.imshow(img)
plt.grid(False)
plt.title("Imagen Original a 150x150",fontsize=16)

# -----------------------------------------------------------------------
# Now let's display our representations
# -----------------------------------------------------------------------
for layer_name, feature_map in zip(layer_names, successive_feature_maps):

    if len(feature_map.shape) == 4:

      #-------------------------------------------
      # Just do this for the conv / maxpool layers, not the fully-connected layers
      #-------------------------------------------
      n_features = feature_map.shape[-1]  # number of features in the feature map
      size       = feature_map.shape[ 1]  # feature map shape (1, size, size, n_features)
      # We will tile our images in this matrix
      display_grid = np.zeros((size, size * n_features))

      #-------------------------------------------------
      # Postprocess the feature to be visually palatable
      #-------------------------------------------------
      for i in range(n_features):
          x  = feature_map[0, :, :, i]
          x -= x.mean()
          x /= x.std ()
          x *=  64
          x += 128
          x  = np.clip(x, 0, 255).astype('uint8')
          display_grid[:, i * size : (i + 1) * size] = x # Tile each filter into a horizontal grid

    #-----------------
    # Display the grid
    #-----------------

    scale = 35. / n_features
    plt.figure(figsize=(scale * n_features, scale))
    plt.title (layer_name, fontsize=18)
    plt.grid (False)
    plt.imshow(display_grid, aspect='auto', cmap='binary') 
    plt.show()
/tmp/ipykernel_51274/3497460116.py:60: RuntimeWarning: invalid value encountered in true_divide
  x /= x.std ()

Gráficas de funciones de pérdida y accuracy¶

In [54]:
#-----------------------------------------------------------
# Retrieve a list of list results on training and test data
# sets for each training epoch
#-----------------------------------------------------------
acc      = history.history[     'accuracy' ]
val_acc  = history.history[ 'val_accuracy' ]
loss     = history.history[    'loss' ]
val_loss = history.history['val_loss' ]

epochs   = range(len(acc)) # Get number of epochs


plt.figure(figsize=(20,8))
#------------------------------------------------
# Plot training and validation accuracy per epoch
#------------------------------------------------
plt.subplot(121)
plt.plot  ( epochs,     acc,'r',label='Training Accuracy' )
plt.plot  ( epochs, val_acc,'b',label='Testing  Accuracy' )
plt.title ('Training and validation accuracy',fontsize=16)
plt.grid()
plt.legend(fontsize=16)
#------------------------------------------------
# Plot training and validation loss per epoch
#------------------------------------------------
plt.subplot(122)
plt.plot  ( epochs,     loss,'r',label='Training Loss' )
plt.plot  ( epochs, val_loss,'b',label='Testing  Loss' )
plt.title ('Training and validation loss',fontsize=16)
plt.grid()
plt.legend(fontsize=16)
plt.show()

Liberar recursos y RAM¶

In [ ]:
import os, signal
os.kill(os.getpid(), signal.SIGKILL)

[Volver al Inicio]

Horse or Human¶

Historia¶

Podremos encontrar un poco de historia sobre este dataset aquĆ­.

Cargar Datos¶

In [55]:
!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip \
    -O /tmp/horse-or-human.zip
--2021-11-12 14:43:24--  https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip
Resolving storage.googleapis.com (storage.googleapis.com)... 172.217.172.16, 172.217.30.208, 172.217.28.112, ...
Connecting to storage.googleapis.com (storage.googleapis.com)|172.217.172.16|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 149574867 (143M) [application/zip]
Saving to: ā€˜/tmp/horse-or-human.zip’

/tmp/horse-or-human 100%[===================>] 142.65M  27.3MB/s    in 5.5s    

2021-11-12 14:43:30 (25.7 MB/s) - ā€˜/tmp/horse-or-human.zip’ saved [149574867/149574867]

In [56]:
!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/validation-horse-or-human.zip \
    -O /tmp/validation-horse-or-human.zip
--2021-11-12 14:43:43--  https://storage.googleapis.com/laurencemoroney-blog.appspot.com/validation-horse-or-human.zip
Resolving storage.googleapis.com (storage.googleapis.com)... 172.217.172.16, 172.217.30.208, 172.217.28.112, ...
Connecting to storage.googleapis.com (storage.googleapis.com)|172.217.172.16|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11480187 (11M) [application/zip]
Saving to: ā€˜/tmp/validation-horse-or-human.zip’

/tmp/validation-hor 100%[===================>]  10.95M  15.3MB/s    in 0.7s    

2021-11-12 14:43:44 (15.3 MB/s) - ā€˜/tmp/validation-horse-or-human.zip’ saved [11480187/11480187]

In [57]:
import os
import zipfile

local_zip = '/tmp/horse-or-human.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/horse-or-human')
local_zip = '/tmp/validation-horse-or-human.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/validation-horse-or-human')
zip_ref.close()
In [59]:
# Directory with our training horse pictures
train_horse_dir = os.path.join('/tmp/horse-or-human/horses')

# Directory with our training human pictures
train_human_dir = os.path.join('/tmp/horse-or-human/humans')

# Directory with our training horse pictures
validation_horse_dir = os.path.join('/tmp/validation-horse-or-human/horses')

# Directory with our training human pictures
validation_human_dir = os.path.join('/tmp/validation-horse-or-human/humans')
In [60]:
train_horse_names = os.listdir(train_horse_dir)
print(train_horse_names[:10])

train_human_names = os.listdir(train_human_dir)
print(train_human_names[:10])

validation_horse_hames = os.listdir(validation_horse_dir)
print(validation_horse_hames[:10])

validation_human_names = os.listdir(validation_human_dir)
print(validation_human_names[:10])
['horse48-6.png', 'horse34-9.png', 'horse13-7.png', 'horse09-8.png', 'horse35-8.png', 'horse28-8.png', 'horse16-0.png', 'horse30-0.png', 'horse08-5.png', 'horse40-0.png']
['human04-19.png', 'human12-19.png', 'human02-03.png', 'human17-17.png', 'human13-10.png', 'human12-28.png', 'human02-01.png', 'human11-03.png', 'human17-24.png', 'human07-06.png']
['horse2-294.png', 'horse3-217.png', 'horse5-103.png', 'horse5-002.png', 'horse5-123.png', 'horse4-468.png', 'horse5-303.png', 'horse5-565.png', 'horse3-397.png', 'horse1-105.png']
['valhuman02-06.png', 'valhuman01-01.png', 'valhuman02-22.png', 'valhuman01-21.png', 'valhuman01-00.png', 'valhuman05-10.png', 'valhuman03-23.png', 'valhuman01-07.png', 'valhuman01-04.png', 'valhuman05-16.png']
In [61]:
print('total training horse images:', len(os.listdir(train_horse_dir)))
print('total training human images:', len(os.listdir(train_human_dir)))
print('total validation horse images:', len(os.listdir(validation_horse_dir)))
print('total validation human images:', len(os.listdir(validation_human_dir)))
total training horse images: 500
total training human images: 527
total validation horse images: 128
total validation human images: 128
In [62]:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

# Parameters for our graph; we'll output images in a 4x4 configuration
nrows = 4
ncols = 4

# Index for iterating over images
pic_index = 0
In [63]:
# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols * 4, nrows * 4)

pic_index += 8
next_horse_pix = [os.path.join(train_horse_dir, fname) 
                for fname in train_horse_names[pic_index-8:pic_index]]
next_human_pix = [os.path.join(train_human_dir, fname) 
                for fname in train_human_names[pic_index-8:pic_index]]

for i, img_path in enumerate(next_horse_pix+next_human_pix):
    # Set up subplot; subplot indices start at 1
    sp = plt.subplot(nrows, ncols, i + 1)
    sp.axis('Off') # Don't show axes (or gridlines)

    img = mpimg.imread(img_path)
    plt.imshow(img)

plt.show()
In [64]:
model = tf.keras.models.Sequential([
    # Note the input shape is the desired size of the image 300x300 with 3 bytes color
    # This is the first convolution
    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(300, 300, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    # The second convolution
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The third convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The fourth convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The fifth convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(),
    # 512 neuron hidden layer
    tf.keras.layers.Dense(512, activation='relu'),
    # Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')
    tf.keras.layers.Dense(1, activation='sigmoid')
])
In [65]:
model.summary()
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_6 (Conv2D)           (None, 298, 298, 16)      448       
                                                                 
 max_pooling2d_6 (MaxPooling  (None, 149, 149, 16)     0         
 2D)                                                             
                                                                 
 conv2d_7 (Conv2D)           (None, 147, 147, 32)      4640      
                                                                 
 max_pooling2d_7 (MaxPooling  (None, 73, 73, 32)       0         
 2D)                                                             
                                                                 
 conv2d_8 (Conv2D)           (None, 71, 71, 64)        18496     
                                                                 
 max_pooling2d_8 (MaxPooling  (None, 35, 35, 64)       0         
 2D)                                                             
                                                                 
 conv2d_9 (Conv2D)           (None, 33, 33, 64)        36928     
                                                                 
 max_pooling2d_9 (MaxPooling  (None, 16, 16, 64)       0         
 2D)                                                             
                                                                 
 conv2d_10 (Conv2D)          (None, 14, 14, 64)        36928     
                                                                 
 max_pooling2d_10 (MaxPoolin  (None, 7, 7, 64)         0         
 g2D)                                                            
                                                                 
 flatten_2 (Flatten)         (None, 3136)              0         
                                                                 
 dense_4 (Dense)             (None, 512)               1606144   
                                                                 
 dense_5 (Dense)             (None, 1)                 513       
                                                                 
=================================================================
Total params: 1,704,097
Trainable params: 1,704,097
Non-trainable params: 0
_________________________________________________________________
In [66]:
from tensorflow.keras.optimizers import RMSprop

model.compile(loss='binary_crossentropy',
              optimizer=Adam(),
              metrics=['accuracy'])
In [67]:
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(rescale=1/255)
validation_datagen = ImageDataGenerator(rescale=1/255)

# Flow training images in batches of 128 using train_datagen generator
train_generator = train_datagen.flow_from_directory(
        '/tmp/horse-or-human/',  # This is the source directory for training images
        target_size=(300, 300),  # All images will be resized to 300x300
        batch_size=128,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode='binary')

# Flow training images in batches of 128 using train_datagen generator
validation_generator = validation_datagen.flow_from_directory(
        '/tmp/validation-horse-or-human/',  # This is the source directory for training images
        target_size=(300, 300),  # All images will be resized to 300x300
        batch_size=32,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode='binary')
Found 1027 images belonging to 2 classes.
Found 256 images belonging to 2 classes.
In [69]:
history = model.fit(
      train_generator,
      steps_per_epoch=8,  
      epochs=15,
      verbose=1,
      validation_data = validation_generator,
      validation_steps=8)
Epoch 1/15
8/8 [==============================] - 4s 503ms/step - loss: 0.0041 - accuracy: 1.0000 - val_loss: 3.3293 - val_accuracy: 0.8203
Epoch 2/15
8/8 [==============================] - 4s 488ms/step - loss: 0.0067 - accuracy: 0.9978 - val_loss: 3.7326 - val_accuracy: 0.7656
Epoch 3/15
8/8 [==============================] - 4s 483ms/step - loss: 0.0052 - accuracy: 0.9978 - val_loss: 1.7279 - val_accuracy: 0.8672
Epoch 4/15
8/8 [==============================] - 4s 491ms/step - loss: 0.0072 - accuracy: 0.9978 - val_loss: 4.0664 - val_accuracy: 0.7461
Epoch 5/15
8/8 [==============================] - 4s 551ms/step - loss: 0.0019 - accuracy: 1.0000 - val_loss: 4.3019 - val_accuracy: 0.7773
Epoch 6/15
8/8 [==============================] - 4s 489ms/step - loss: 0.0010 - accuracy: 1.0000 - val_loss: 3.6802 - val_accuracy: 0.8125
Epoch 7/15
8/8 [==============================] - 4s 542ms/step - loss: 6.6223e-04 - accuracy: 1.0000 - val_loss: 3.6925 - val_accuracy: 0.8203
Epoch 8/15
8/8 [==============================] - 4s 484ms/step - loss: 3.0292e-04 - accuracy: 1.0000 - val_loss: 3.7078 - val_accuracy: 0.8242
Epoch 9/15
8/8 [==============================] - 4s 501ms/step - loss: 2.4854e-04 - accuracy: 1.0000 - val_loss: 3.7560 - val_accuracy: 0.8242
Epoch 10/15
8/8 [==============================] - 4s 498ms/step - loss: 1.8106e-04 - accuracy: 1.0000 - val_loss: 3.8736 - val_accuracy: 0.8203
Epoch 11/15
8/8 [==============================] - 4s 483ms/step - loss: 1.5875e-04 - accuracy: 1.0000 - val_loss: 3.8773 - val_accuracy: 0.8203
Epoch 12/15
8/8 [==============================] - 4s 488ms/step - loss: 1.3453e-04 - accuracy: 1.0000 - val_loss: 3.8154 - val_accuracy: 0.8320
Epoch 13/15
8/8 [==============================] - 4s 484ms/step - loss: 1.1901e-04 - accuracy: 1.0000 - val_loss: 3.8575 - val_accuracy: 0.8281
Epoch 14/15
8/8 [==============================] - 4s 491ms/step - loss: 9.2547e-05 - accuracy: 1.0000 - val_loss: 3.8898 - val_accuracy: 0.8281
Epoch 15/15
8/8 [==============================] - 4s 480ms/step - loss: 9.5020e-05 - accuracy: 1.0000 - val_loss: 3.9102 - val_accuracy: 0.8320
In [71]:
model.save('../Datos/Horses_or_Humans.h5')
In [ ]:
model=tf.keras.models.load_model('../Datos/Horses_or_Humans.h5')
In [ ]:
import numpy as np
from google.colab import files
from keras.preprocessing import image

uploaded = files.upload()

for fn in uploaded.keys():
 
  # predicting images
  path = '/content/' + fn
  img = image.load_img(path, target_size=(300, 300))
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)

  images = np.vstack([x])
  classes = model.predict(images, batch_size=10)
  print(classes[0])
  if classes[0]>0:
    print(fn + " is a human")
  else:
    print(fn + " is a horse")
Upload widget is only available when the cell has been executed in the current browser session. Please rerun this cell to enable.
In [ ]:
import numpy as np
import random
from tensorflow.keras.preprocessing.image import img_to_array, load_img

# Let's define a new Model that will take an image as input, and will output
# intermediate representations for all layers in the previous model after
# the first.
successive_outputs = [layer.output for layer in model.layers[1:]]
#visualization_model = Model(img_input, successive_outputs)
visualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs)
# Let's prepare a random input image from the training set.
horse_img_files = [os.path.join(train_horse_dir, f) for f in train_horse_names]
human_img_files = [os.path.join(train_human_dir, f) for f in train_human_names]
img_path = random.choice(horse_img_files + human_img_files)

img = load_img(img_path, target_size=(300, 300))  # this is a PIL image
x = img_to_array(img)  # Numpy array with shape (150, 150, 3)
x = x.reshape((1,) + x.shape)  # Numpy array with shape (1, 150, 150, 3)

# Rescale by 1/255
x /= 255

# Let's run our image through our network, thus obtaining all
# intermediate representations for this image.
successive_feature_maps = visualization_model.predict(x)

# These are the names of the layers, so can have them as part of our plot
layer_names = [layer.name for layer in model.layers[:-2]]

# Mostrar Imagen Original
plt.figure()
plt.imshow(img)
plt.grid(False)
plt.title("Imagen Original a 300x300",fontsize=16)

# Now let's display our representations
for layer_name, feature_map in zip(layer_names, successive_feature_maps):
  if len(feature_map.shape) == 4:
    # Just do this for the conv / maxpool layers, not the fully-connected layers
    n_features = feature_map.shape[-1]  # number of features in feature map
    # The feature map has shape (1, size, size, n_features)
    size = feature_map.shape[1]
    # We will tile our images in this matrix
    display_grid = np.zeros((size, size * n_features))
    for i in range(n_features):
      # Postprocess the feature to make it visually palatable
      x = feature_map[0, :, :, i]
      x -= x.mean()
      x /= x.std()
      x *= 64
      x += 128
      x = np.clip(x, 0, 255).astype('uint8')
      # We'll tile each filter into this big horizontal grid
      display_grid[:, i * size : (i + 1) * size] = x
    # Display the grid
    scale = 20. / n_features
    plt.figure(figsize=(scale * n_features, scale))
    plt.title(layer_name)
    plt.grid(False)
    plt.imshow(display_grid, aspect='auto', cmap='binary')
/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:49: RuntimeWarning: invalid value encountered in true_divide
In [ ]:
import os, signal
os.kill(os.getpid(), signal.SIGKILL)

[Volver al Inicio]

Piedra Papel o Tijeras ¶

Este ejemplo es un poco mÔs complejo, pues haremos clasificación en tres clases de manos de diferentes tipos.

Las manos humanas tienen muchos rasgos distintos que hace que el proceso de clasificación no sea trivial.

Cargar Datos¶

In [ ]:
!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps.zip \
    -O /tmp/rps.zip
  
!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps-test-set.zip \
    -O /tmp/rps-test-set.zip
--2020-10-08 19:45:43--  https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps.zip
Resolving storage.googleapis.com (storage.googleapis.com)... 108.177.119.128, 108.177.126.128, 108.177.127.128, ...
Connecting to storage.googleapis.com (storage.googleapis.com)|108.177.119.128|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 200682221 (191M) [application/zip]
Saving to: ā€˜/tmp/rps.zip’

/tmp/rps.zip        100%[===================>] 191.38M  45.1MB/s    in 4.2s    

2020-10-08 19:45:47 (45.1 MB/s) - ā€˜/tmp/rps.zip’ saved [200682221/200682221]

--2020-10-08 19:45:48--  https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps-test-set.zip
Resolving storage.googleapis.com (storage.googleapis.com)... 108.177.126.128, 108.177.127.128, 172.217.218.128, ...
Connecting to storage.googleapis.com (storage.googleapis.com)|108.177.126.128|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 29516758 (28M) [application/zip]
Saving to: ā€˜/tmp/rps-test-set.zip’

/tmp/rps-test-set.z 100%[===================>]  28.15M  74.3MB/s    in 0.4s    

2020-10-08 19:45:48 (74.3 MB/s) - ā€˜/tmp/rps-test-set.zip’ saved [29516758/29516758]

In [ ]:
import os
import zipfile

local_zip = '/tmp/rps.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/')
zip_ref.close()

local_zip = '/tmp/rps-test-set.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/')
zip_ref.close()
In [ ]:
rock_dir = os.path.join('/tmp/rps/rock')
paper_dir = os.path.join('/tmp/rps/paper')
scissors_dir = os.path.join('/tmp/rps/scissors')

print('total training rock images:', len(os.listdir(rock_dir)))
print('total training paper images:', len(os.listdir(paper_dir)))
print('total training scissors images:', len(os.listdir(scissors_dir)))

rock_files = os.listdir(rock_dir)
print(rock_files[:10])

paper_files = os.listdir(paper_dir)
print(paper_files[:10])

scissors_files = os.listdir(scissors_dir)
print(scissors_files[:10])
total training rock images: 840
total training paper images: 840
total training scissors images: 840
['rock01-071.png', 'rock02-049.png', 'rock06ck02-078.png', 'rock01-012.png', 'rock01-049.png', 'rock01-092.png', 'rock01-114.png', 'rock05ck01-053.png', 'rock06ck02-021.png', 'rock02-113.png']
['paper05-107.png', 'paper01-072.png', 'paper04-025.png', 'paper05-097.png', 'paper03-048.png', 'paper03-029.png', 'paper02-032.png', 'paper02-013.png', 'paper01-045.png', 'paper06-081.png']
['scissors04-088.png', 'scissors01-052.png', 'scissors02-061.png', 'scissors02-080.png', 'testscissors03-031.png', 'scissors04-073.png', 'scissors02-063.png', 'scissors02-027.png', 'scissors01-017.png', 'testscissors01-117.png']
In [ ]:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

pic_index = 2

next_rock = [os.path.join(rock_dir, fname) 
                for fname in rock_files[pic_index-2:pic_index]]
next_paper = [os.path.join(paper_dir, fname) 
                for fname in paper_files[pic_index-2:pic_index]]
next_scissors = [os.path.join(scissors_dir, fname) 
                for fname in scissors_files[pic_index-2:pic_index]]

for i, img_path in enumerate(next_rock+next_paper+next_scissors):
  #print(img_path)
  img = mpimg.imread(img_path)
  plt.imshow(img)
  plt.axis('Off')
  plt.show()

Aumentando Datos¶

Una técnica natural en DL para obtener datos sintéticos que pueden ayudar a la red neuronal es mediante la técnica llamada aumentación de datos (Data augmentation)

Vemos un blog al respecto:

Exploring Data Augmentation with Keras and TensorFlow

In [ ]:
import tensorflow as tf
import keras_preprocessing
from keras_preprocessing import image
from keras_preprocessing.image import ImageDataGenerator

TRAINING_DIR = "/tmp/rps/"
training_datagen = ImageDataGenerator(
      rescale = 1./255,
	    rotation_range=40,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,
      fill_mode='nearest')

VALIDATION_DIR = "/tmp/rps-test-set/"

validation_datagen = ImageDataGenerator(rescale = 1./255)

train_generator = training_datagen.flow_from_directory(
	TRAINING_DIR,
	target_size=(150,150),
	class_mode='categorical',
  batch_size=126
)

validation_generator = validation_datagen.flow_from_directory(
	VALIDATION_DIR,
	target_size=(150,150),
	class_mode='categorical',
  batch_size=126
)

model = tf.keras.models.Sequential([
    # Note the input shape is the desired size of the image 150x150 with 3 bytes color
    # This is the first convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    # The second convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The third convolution
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The fourth convolution
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.5),
    # 512 neuron hidden layer
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dense(3, activation='softmax')
])


model.summary()

model.compile(loss = 'categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

history = model.fit(train_generator, epochs=25, steps_per_epoch=20, validation_data = validation_generator, verbose = 1, validation_steps=3)

model.save("rps.h5")
Found 2520 images belonging to 3 classes.
Found 372 images belonging to 3 classes.
Model: "sequential_7"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_17 (Conv2D)           (None, 148, 148, 64)      1792      
_________________________________________________________________
max_pooling2d_17 (MaxPooling (None, 74, 74, 64)        0         
_________________________________________________________________
conv2d_18 (Conv2D)           (None, 72, 72, 64)        36928     
_________________________________________________________________
max_pooling2d_18 (MaxPooling (None, 36, 36, 64)        0         
_________________________________________________________________
conv2d_19 (Conv2D)           (None, 34, 34, 128)       73856     
_________________________________________________________________
max_pooling2d_19 (MaxPooling (None, 17, 17, 128)       0         
_________________________________________________________________
conv2d_20 (Conv2D)           (None, 15, 15, 128)       147584    
_________________________________________________________________
max_pooling2d_20 (MaxPooling (None, 7, 7, 128)         0         
_________________________________________________________________
flatten_7 (Flatten)          (None, 6272)              0         
_________________________________________________________________
dropout (Dropout)            (None, 6272)              0         
_________________________________________________________________
dense_14 (Dense)             (None, 512)               3211776   
_________________________________________________________________
dense_15 (Dense)             (None, 3)                 1539      
=================================================================
Total params: 3,473,475
Trainable params: 3,473,475
Non-trainable params: 0
_________________________________________________________________
Epoch 1/25
20/20 [==============================] - 18s 913ms/step - loss: 1.7653 - accuracy: 0.3508 - val_loss: 1.1284 - val_accuracy: 0.3333
Epoch 2/25
20/20 [==============================] - 18s 885ms/step - loss: 1.0951 - accuracy: 0.3845 - val_loss: 1.0036 - val_accuracy: 0.3333
Epoch 3/25
20/20 [==============================] - 18s 885ms/step - loss: 1.1114 - accuracy: 0.3786 - val_loss: 1.0552 - val_accuracy: 0.7366
Epoch 4/25
20/20 [==============================] - 18s 884ms/step - loss: 1.0968 - accuracy: 0.4508 - val_loss: 0.8790 - val_accuracy: 0.5511
Epoch 5/25
20/20 [==============================] - 18s 895ms/step - loss: 1.1299 - accuracy: 0.5294 - val_loss: 0.9576 - val_accuracy: 0.5188
Epoch 6/25
20/20 [==============================] - 18s 885ms/step - loss: 0.8538 - accuracy: 0.6107 - val_loss: 1.1898 - val_accuracy: 0.4516
Epoch 7/25
20/20 [==============================] - 18s 884ms/step - loss: 0.8080 - accuracy: 0.6524 - val_loss: 0.3756 - val_accuracy: 0.9409
Epoch 8/25
20/20 [==============================] - 18s 889ms/step - loss: 0.7358 - accuracy: 0.6754 - val_loss: 0.2819 - val_accuracy: 0.9516
Epoch 9/25
20/20 [==============================] - 18s 892ms/step - loss: 0.5776 - accuracy: 0.7536 - val_loss: 0.2242 - val_accuracy: 0.8871
Epoch 10/25
20/20 [==============================] - 18s 885ms/step - loss: 0.5687 - accuracy: 0.7675 - val_loss: 0.6149 - val_accuracy: 0.5591
Epoch 11/25
20/20 [==============================] - 18s 883ms/step - loss: 0.4737 - accuracy: 0.8079 - val_loss: 0.4801 - val_accuracy: 0.7097
Epoch 12/25
20/20 [==============================] - 18s 882ms/step - loss: 0.2945 - accuracy: 0.8889 - val_loss: 0.5513 - val_accuracy: 0.7661
Epoch 13/25
20/20 [==============================] - 18s 888ms/step - loss: 0.3896 - accuracy: 0.8385 - val_loss: 0.1320 - val_accuracy: 0.9328
Epoch 14/25
20/20 [==============================] - 18s 887ms/step - loss: 0.2583 - accuracy: 0.9012 - val_loss: 0.0343 - val_accuracy: 0.9919
Epoch 15/25
20/20 [==============================] - 18s 882ms/step - loss: 0.2377 - accuracy: 0.9107 - val_loss: 0.0546 - val_accuracy: 0.9946
Epoch 16/25
20/20 [==============================] - 18s 889ms/step - loss: 0.1675 - accuracy: 0.9421 - val_loss: 0.1157 - val_accuracy: 0.9516
Epoch 17/25
20/20 [==============================] - 18s 889ms/step - loss: 0.2228 - accuracy: 0.9187 - val_loss: 0.0418 - val_accuracy: 0.9866
Epoch 18/25
20/20 [==============================] - 18s 894ms/step - loss: 0.1443 - accuracy: 0.9488 - val_loss: 0.0593 - val_accuracy: 0.9758
Epoch 19/25
20/20 [==============================] - 18s 882ms/step - loss: 0.2072 - accuracy: 0.9306 - val_loss: 0.0770 - val_accuracy: 0.9731
Epoch 20/25
20/20 [==============================] - 18s 884ms/step - loss: 0.1307 - accuracy: 0.9556 - val_loss: 0.1056 - val_accuracy: 0.9489
Epoch 21/25
20/20 [==============================] - 18s 888ms/step - loss: 0.2696 - accuracy: 0.9004 - val_loss: 0.0433 - val_accuracy: 0.9839
Epoch 22/25
20/20 [==============================] - 18s 888ms/step - loss: 0.1245 - accuracy: 0.9512 - val_loss: 1.1970 - val_accuracy: 0.6667
Epoch 23/25
20/20 [==============================] - 18s 885ms/step - loss: 0.2026 - accuracy: 0.9508 - val_loss: 0.1453 - val_accuracy: 0.9516
Epoch 24/25
20/20 [==============================] - 18s 883ms/step - loss: 0.1183 - accuracy: 0.9548 - val_loss: 0.0200 - val_accuracy: 1.0000
Epoch 25/25
20/20 [==============================] - 18s 883ms/step - loss: 0.0956 - accuracy: 0.9651 - val_loss: 0.0218 - val_accuracy: 0.9892
In [ ]:
import matplotlib.pyplot as plt
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.figure(figsize=(18,5))
#------------------------------------------------
# Plot training and validation accuracy per epoch
#------------------------------------------------
plt.subplot(121)
plt.plot  ( epochs,     acc,'r',label='Training Accuracy' )
plt.plot  ( epochs, val_acc,'b',label='Testing  Accuracy' )
plt.title ('Training and validation accuracy',fontsize=16)
plt.grid()
plt.legend(fontsize=16)
#------------------------------------------------
# Plot training and validation loss per epoch
#------------------------------------------------
plt.subplot(122)
plt.plot  ( epochs,     loss,'r',label='Training Loss' )
plt.plot  ( epochs, val_loss,'b',label='Testing  Loss' )
plt.title ('Training and validation loss',fontsize=16)
plt.grid()
plt.legend(fontsize=16)
plt.show()
In [ ]:
model=tf.keras.models.load_model('rps.h5')
In [ ]:
preds=model.predict(validation_generator)
preds[:5]
WARNING:tensorflow:5 out of the last 54 calls to <function Model.make_predict_function.<locals>.predict_function at 0x7f442cf9cea0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
Out[ ]:
array([[6.1073937e-09, 9.9999928e-01, 6.6503407e-07],
       [1.4923323e-07, 9.9999988e-01, 1.0823758e-08],
       [8.9176693e-09, 9.9999952e-01, 4.2809245e-07],
       [9.9999690e-01, 2.6853102e-06, 3.9489521e-07],
       [9.9999976e-01, 1.2737560e-07, 1.3945728e-07]], dtype=float32)
In [ ]:
import numpy as np
from google.colab import files
from keras.preprocessing import image

uploaded = files.upload()

for fn in uploaded.keys():
 
  # predicting images
  path = fn
  img = image.load_img(path, target_size=(150, 150))
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)

  images = np.vstack([x])
  classes = model.predict(images, batch_size=10)
  print(fn)
  print(classes)

  ## [paper,rock,scissors]
Upload widget is only available when the cell has been executed in the current browser session. Please rerun this cell to enable.
Saving 2020-10-08-113519.jpg to 2020-10-08-113519 (4).jpg
WARNING:tensorflow:6 out of the last 57 calls to <function Model.make_predict_function.<locals>.predict_function at 0x7f442cf9cea0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
2020-10-08-113519.jpg
[[0. 1. 0.]]

Conclusión: A jugar!

[Volver al Inicio]